define('framework/datatree/GillionDataTreeDirectiveConstructor',
    ['angular','jquery'], function (angular,$) {
        return function($compile,Arrays,$dataSourceManager,$templateCache,$timeout) {
            var recursiveTemplate, template;
            template =  '<div class="tree">'+
                        '   <div ng-disabled="disabled" class="tree-head">'+
                        '      <ul class="tree-head-selecteds">'+
                        '         <li>选择：</li>'+
                        '         <li ng-disabled="disabled" ng-repeat="item in _chooseItems" ng-click="deleteChooseItem(item)">{{item.displayExpress}}</li>'+
                        '      </ul>'+
                        '      <button ng-disabled="disabled" class="btn tree-btn-reset"  ng-click="clearChooseItems()">重选</button>'+
                        '   </div>'+
                        '   <div class="tree-body">'+
                        '   <ul ng-include="\'/datatree/template\'"></ul>'+
                        '   </div>'+
                        '</div>';

            recursiveTemplate = '<li ng-if="(!item.type || item.type===\'branch\') &&  item.expanded" open="true"  ng-repeat-start="item in treeData">'+
                                '   <div class="tree-item"  ng-click="setCurrentRow(item)">'+
                                '      <i class="fi tree-fi-folder" ng-click="expandNode(item)"></i>'+
                                '      <i ng-if="!radio && item.checked && item.showBox && allowChooseParent" class="fi tree-fi-clickbox" selected="selected" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="!radio && !item.checked && item.showBox && allowChooseParent" class="fi tree-fi-clickbox" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="!item.showBox || radio" class="fi tree-fi-clickbox" canchoose="false" ng-click="chooseItem(item)"></i>'+
                                '      <span>{{item.displayExpress}}</span>'+
                                '   </div>'+
                                '   <ul ng-include="\'/datatree/template\'" ng-init="treeData=item.children"></ul>'+
                                '</li>'+

                                '<li ng-if="(!item.type || item.type===\'branch\') &&  !item.expanded" >'+
                                '   <div class="tree-item" ng-click="setCurrentRow(item)">'+
                                '      <i class="fi tree-fi-folder" ng-click="expandNode(item)"></i>'+
                                '      <i ng-if="!radio && item.checked && item.showBox && allowChooseParent" class="fi tree-fi-clickbox" selected="selected" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="!radio && !item.checked && item.showBox && allowChooseParent" class="fi tree-fi-clickbox" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="!item.showBox || radio || !allowChooseParent" class="fi tree-fi-clickbox" canchoose="false" ng-click="chooseItem(item)"></i>'+
                                '      <span>{{item.displayExpress}}</span>'+
                                '   </div>'+
                                '   <ul ng-include="\'/datatree/template\'" ng-init="treeData=item.children"></ul>'+
                                '</li>'+

                                '<li ng-if="item.type === \'leaf\'" ng-repeat-end>'+
                                '    <div class="tree-item"  leaf="true" ng-click="setCurrentRow(item)">'+
                                '      <i class="fi tree-fi-folder"></i>'+
                                '      <i ng-if="radio && item.checked && item.showBox" class="fi tree-fi-clickbox" mode="radio" selected="selected" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="radio && !item.checked && item.showBox" class="fi tree-fi-clickbox"  mode="radio" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="!radio && item.checked && item.showBox" class="fi tree-fi-clickbox" selected="selected" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="!radio && !item.checked && item.showBox" class="fi tree-fi-clickbox" ng-click="chooseItem(item)"></i>'+
                                '      <i ng-if="!item.showBox" class="fi tree-fi-clickbox" canchoose="false"></i>'+
                                '      <span>{{item.displayExpress}}</span>'+
                                '    </div>'+
                                '</li>';
            $templateCache.put("/datatree/template",recursiveTemplate);

            //生成结点
            function createNode(item,config){
                var  prop = config.idProp,
                    parentProp = config.parentProp,
                    hasChildProp = config.hasChildProp,
                    valueProp = config.valueProp,
                    displayExpress = config.displayExpress,
                    showBox = config.showBox,
                    isExpandAll = config.isExpandAll,
                    async = config.async,
                    ele,el,show;
                el = item;
                ele = {};
                ele.idProp = el[prop];
                ele.parentProp = el[parentProp];
                ele.valueProp= el[valueProp];
                ele.displayExpress = el[displayExpress];
                ele.showBox = true;
                if(angular.isFunction(showBox())){
                    ele.showBox = (showBox()(el)===true);
                }else{
                    show = showBox(el);
                    if(show!==undefined){
                        ele.showBox = (show===true);
                    }
                }
                ele.originData=el;
                ele.checked=false;
                ele.children=[];

                ele.expanded=false;
                if(async==="true"){
                    if(el[hasChildProp]==='true' || el[hasChildProp]===true || !hasChildProp){
                        ele.type="branch";
                    }else{
                        ele.type="leaf";
                    }
                }else{
                    ele.type="leaf";
                    if(isExpandAll==="true"){
                        ele.expanded=true;
                    }
                }
                return ele;
            }

            //构建树
            function buildTree(source,config) {
                source = angular.copy(source);
                var prop = config.idProp,
                    parentProp = config.parentProp,
                    results = [],
                    fetchChildrenFn,
                    margin, i, len, el,ele;
                fetchChildrenFn = function (element, margin) {
                    if (margin.length === 0) return;
                    var children = [],
                        i, len, el, childrenMargin,ele,show;
                    for (i = 0, len = margin.length; i < len; i++) {
                        el = margin[i];
                        if (el[parentProp] === element.idProp) {
                            ele = {};
                            ele = createNode(el,config);
                            children.push(ele);
                            ele = null;
                        }
                    }
                    childrenMargin = Arrays.subtract(margin, children);
                    for (i = 0, len = children.length; i < len; i++) {
                        el = children[i] = angular.copy(children[i]);
                        fetchChildrenFn(el, childrenMargin);
                    }
                    if (children.length > 0) {
                        element.children = children;
                        element.type="branch";
                    }
                }

                if(!source || source.length===0){
                    return results;
                }
                for (i = 0, len = source.length; i < len; i++) {
                    el = source[i];
                    if (!el[parentProp]) {
                        ele = {};
                        ele =  createNode(el,config);
                        results.push(ele);
                        ele = null;
                    }
                }
                margin = Arrays.subtract(source, results);
                // copy放在下面是为了subtract使用'==='而不是equals， 效率更高
                for (i = 0, len = results.length; i < len; i++) {
                    el = results[i] = angular.copy(results[i]);
                    fetchChildrenFn(el, margin);
                }
                return results;
            }

            //加载子结点
            function transcateChildren(records,config){
                var i,len,result,el,ele;
                result=[];
                for(i=0,len=records.length;i<len;i++){
                    el = records[i];
                    ele = {};
                    ele = createNode(el,config)
                    result.push(ele);
                }
                return result;
            }

            //根据id查找结点
            function searchNodeByTd(treeData,id){
                var i,len,el,result,childRes;
                for(i=0, len = treeData.length; i<len; i++){
                    el = treeData[i];
                    if(el.idProp === id){
                        result=el;
                        break;
                    }
                    if(el.children && el.children.length>0){
                        childRes = arguments.callee(el.children,id);
                    }
                    if(childRes){
                        result = childRes;
                        break;
                    }
                }
                return result;
            }

            //根据值查找结点
            function findNodeByValue(treeData,value){
                var result=[],childItems=[],
                    i,len,el;
                for(i=0, len=treeData.length; i<len; i++){
                    el = treeData[i];
                    if(el.valueProp===value){
                        result.push(el);
                    }
                    if(el.children && el.children.length>0){
                        childItems = arguments.callee(el.children,value);
                    }
                    if(childItems && childItems.length>0){
                        result = result.concat(childItems);
                        childItems = [] ;
                    }
                }
                return result;
            }


            return {
                restrict: 'E',
                replace:true,
                scope:{
                    currentRow:'=',
                    sourceName:'@',
                    showSelect:'&',
                    disabled:'@',
                    chooseItems:'=',
                    onBeforeSelect:'&',
                    onSelect:'&',
                    onBeforeCheck:'&',
                    onCheck:'&'
                },
                require:'?^ngModel',
                template:template,
                link:function(scope,element,attrs,ngModel){
                    var displayExpress = attrs.displayExpress,
                        valueProp=attrs.valueProp,
                        parentProp=attrs.parentProp,
                        idProp = attrs.idProp,
                        hasChildProp = attrs.hasChildProp,
                        mode = attrs.mode||'radio',
                        isExpandAll = attrs.isExpandAll || 'false',
                        async = attrs.async || 'false',
                        allowCascadeSelect = attrs.allowCascadeSelect || 'false',
                        allowChooseParent = attrs.allowChooseParent || 'true',
                        width = attrs.width,
                        height = attrs.height,
                        config,selectChild,unSelectChildren,clearChooseItems,unitRegExp,loadTreeData,initTreeData;

                    //保存当前行数据
                    scope.currentRow={};
                    //表示数据源中树关系字段
                    config = {};
                    config.idProp = idProp;
                    config.parentProp = parentProp;
                    config.hasChildProp = hasChildProp;
                    config.valueProp = valueProp;
                    config.displayExpress = displayExpress;
                    config.async = async;
                    config.showBox = scope.showSelect;
                    config.isExpandAll = isExpandAll;

                    scope.radio = (mode==='radio');
                    scope.allowChooseParent = (allowChooseParent==='true');
                    //已选中的记录
                    scope._chooseItems = [];
                    //已经转化好的树型数据
                    scope.treeData = [];

                    //设置控件的宽度
                    unitRegExp = /^[0-9]+(%|in|cm|mm|pt|pc|ex|em|px)?$/g;
                    if(width){
                        if(unitRegExp.test(width)){
                            element.css("width",width);
                        }else{
                            throw "宽度设置错误";
                        }
                    }
                    //设置控件的高度
                    unitRegExp = /^[0-9]+(%|in|cm|mm|pt|pc|ex|em|px)?$/g;
                    if(height){
                        if(unitRegExp.test(height)){
                            element.css("height",height);
                        }else{
                            throw "高度设置错误";
                        }
                    }

                    //初始化数据
                    initTreeData = function(dataSource){
                        var records;
                        records = angular.copy(dataSource.records);
                        if(!scope.source) {
                            scope.source = dataSource;
                        }
                        scope.treeData = buildTree(records,config);
                    }

                    //加载数据
                    $dataSourceManager.getDataSource(scope.sourceName).then(function(dataSource){
                        dataSource.doRequestData({},initTreeData);
                    });

                    //展开树枝结点函数
                    scope.expandNode = function(itemData){
                        if(angular.isUndefined(scope.disabled)){
                            if(async==="true"){
                                scope.source.params = {
                                    id:itemData.idProp
                                }
                                $dataSourceManager.getDataSource(scope.sourceName).then(function(dataSource){
                                    dataSource.doRequestData(scope.source.params,function(_dataSource){
                                        var records,children;
                                        records = angular.copy(_dataSource.records);
                                        if(itemData){
                                            if(!records || records.length===0){
                                                itemData.type="leaf";
                                            }else{
                                                children = transcateChildren(records,config);
                                                angular.extend(itemData.children,children);
                                            }
                                        }
                                    });
                                });
                            }
                            itemData.expanded=!itemData.expanded;
                        }
                    }

                    //选中结点的所有子孙
                    selectChild = function(item){
                        var i,len,el,children;
                        children = item.children || [];
                        for(i=0,len=children.length; i<len; i++){
                            el = children[i];
                            //可以选择，并且还没有被选中
                            if(el.showBox === true && el.checked===false){
                                el.checked = true;
                                scope._chooseItems.push(el);
                                if(el.children && el.children.length>0){
                                    arguments.callee(el);
                                }
                            }
                        }
                    }

                    //从选中数据中删除结点的所有子孙
                    unSelectChildren = function(item){
                        var i,len,el,children;
                        children = item.children || [];
                        for(i=0,len=children.length; i<len; i++){
                            el = children[i];
                            //删除已经被选中的结点
                            if(el.showBox === true && el.checked===true){
                                el.checked = false;
                                Arrays.remove(scope._chooseItems,el);
                                if(el.children && el.children.length>0){
                                    arguments.callee(el);
                                }
                            }
                        }
                    }

                    clearChooseItems = function(){
                        var i,len;
                        for(i=0,len=scope._chooseItems.length;i<len;i++){
                            scope._chooseItems[i].checked=false;
                        }
                        scope._chooseItems=[];
                    }

                    //点击勾选框后执行的函数
                    scope.chooseItem = function(item){
                        var i,len,flag=false,beforeCheck;
                        //判断是否可选
                        if(item.showBox && angular.isUndefined(scope.disabled)){
                            if(scope.radio){
                                if(item.type==='leaf'){
                                    flag = true;
                                }
                            }else{
                                if(item.type==='leaf'){
                                    flag=true;
                                }else if(scope.allowChooseParent){
                                    flag=true;
                                }
                            }
                        }
                        //beforeCheck事件
                        if(angular.isDefined(scope.onBeforeCheck)){
                            if(angular.isFunction(scope.onBeforeCheck())){
                                beforeCheck = scope.onBeforeCheck()(item.originData);
                            }
                        }
                        if(flag && beforeCheck!==false){
                            item.checked = !item.checked;
                            if(scope.radio){
                                clearChooseItems();
                            }
                            if(item.checked===true){
                                scope._chooseItems.push(item);
                                //级联添加
                                if(allowCascadeSelect==='true' && !scope.radio && async==='false'){
                                    selectChild(item);
                                }
                            }else{
                                Arrays.remove(scope._chooseItems,item);
                                //级联删除
                                if(allowCascadeSelect==='true' && !scope.radio && async==='false'){
                                    unSelectChildren(item);
                                }
                            }
                            //onCheck事件
                            if(angular.isDefined(scope.onCheck)){
                                if(angular.isFunction(scope.onCheck())){
                                    beforeCheck = scope.onCheck()(item.originData);
                                }
                            }
                        }
                    }


                    //点击上面选中值文字执行的函数
                    scope.deleteChooseItem = function(item){
                        if(angular.isUndefined(scope.disabled)){
                            Arrays.remove(scope._chooseItems,item);
                            item.checked=false;
                            //级联删除
                            if(allowCascadeSelect==='true' && !scope.radio && async==='false'){
                                unSelectChildren(item);
                            }
                        }
                    }

                    //点击重选执行的函数
                    scope.clearChooseItems = function(){
                        if(angular.isUndefined(scope.disabled)){
                            clearChooseItems();
                        }
                    }

                    //改变当前行函数
                    scope.setCurrentRow = function(item){
                        var el,beforeSelect;
                        if(angular.isDefined(scope.onBeforeSelect)){
                            if(angular.isFunction(scope.onBeforeSelect())){
                                beforeSelect = scope.onBeforeSelect()(item.originData);
                            }
                        }
                        if(angular.isUndefined(scope.disabled) && beforeSelect!==false){
                            el = item.originData;
                            scope.currentRow = el;
                            if(angular.isDefined(scope.onSelect)){
                                if(angular.isFunction(scope.onSelect())){
                                    scope.onSelect()(item.originData);
                                }
                            }
                        }
                    }

                    if(ngModel){
                        ngModel.$render = function(){
                            var modelValues,itemValues,items, i,len,el,_i,_len;
                            clearChooseItems();
                            modelValues = ngModel.$viewValue;
                            if(!modelValues) return;
                            if(scope.radio){
                                items = findNodeByValue(scope.treeData,modelValues);
                                if(items && items.length>0){
                                    if(items[0].showBox && items[0].type==="leaf"){
                                        items[0].checked = true;
                                        scope._chooseItems.push(items[0]);
                                    }
                                }
                            }else{
                                if(modelValues && modelValues.length>0){
                                    itemValues = modelValues.split(",");
                                }
                                for(i=0,len=itemValues.length;i<len;i++){
                                    items =  findNodeByValue(scope.treeData,itemValues[i]);
                                    if(items && items.length>0){
                                        for(_i=0,_len=items.length;_i<_len;_i++){
                                            el = items[_i];
                                            if((el.showBox && scope.allowChooseParent && el.type==="branch") || (el.type==="leaf" && el.showBox)){
                                                el.checked=true;
                                                scope._chooseItems.push(el);
                                            }
                                        }
                                    }
                                }
                            }
                        };

                        //当树中已选中项发生改就时，更改ngModel的值。
                        scope.$watchCollection("_chooseItems",function(newValue,oldValue){
                            var chooseItems=[],modelValue="";
                            angular.forEach(newValue,function(item){
                                modelValue += item.valueProp+",";
                                chooseItems.push(item.originData);
                            });
                            scope.chooseItems = chooseItems;
                            chooseItems = null;
                            if(modelValue && modelValue.length>0){
                                modelValue=modelValue.substring(0,modelValue.length-1);
                            }
                            if (ngModel.$viewValue !== modelValue) {
                                if (scope.$root.$$phase) {
                                    ngModel.$setViewValue(modelValue);
                                } else {
                                    scope.$apply(function () {
                                        ngModel.$setViewValue(modelValue);
                                    });
                                }
                            }
                        });
                    }
                }
            }
        }
    });